package com.example.ntweixin.service;

import com.example.ntweixin.dao.WeixinAccessTokenLogDao;
import com.example.ntweixin.dto.wx.JsapiTicketDto;
import com.example.ntweixin.dto.wx.ReceiveAccessTokenDto;
import com.example.ntweixin.entity.WeixinAccessTokenLog;
import com.example.ntweixin.entity.WeixinPublic;
import com.example.ntweixin.exception.ServerException;
import com.example.ntweixin.utils.HttpUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import com.example.ntweixin.entity.WeixinAccessToken;
import com.example.ntweixin.dao.WeixinAccessTokenDao;

@Service
public class WeixinAccessTokenService{

    private static String ACCESS_TOKEN = null;
    private static Integer EXPIRES_IN = null;
    private static Date SEND_TIME = null;

    private static final Logger logger = LoggerFactory.getLogger(WeixinAccessTokenService.class);
    @Autowired
    private WeixinConf weixinConf;
    @Resource
    private WeixinAccessTokenDao weixinAccessTokenDao;
    @Autowired
    private WeixinAccessTokenLogDao weixinAccessTokenLogDao;

    @Autowired
    private WeixinPublicService weixinPublicService;

    public int insert(WeixinAccessToken pojo){
        return weixinAccessTokenDao.insert(pojo);
    }

    public int insertSelective(WeixinAccessToken pojo){
        return weixinAccessTokenDao.insertSelective(pojo);
    }

    public int insertList(List<WeixinAccessToken> pojos){
        return weixinAccessTokenDao.insertList(pojos);
    }

    public int update(WeixinAccessToken pojo){
        return weixinAccessTokenDao.update(pojo);
    }

    public String getAccessToken() throws ServerException {
        WeixinAccessToken weixinAccessToken = weixinAccessTokenDao.getByWeixinPublicId(weixinConf.getPublicId());
        if (weixinAccessToken == null) {
            // 数据库中没有AccessToken信息，从微信服务器获取AccessToken
            ReceiveAccessTokenDto dto = receiveAccessToken();
            weixinAccessToken = dtoToEntity(dto);
            WeixinAccessTokenLog log = dtoToEntityLog(dto);

            weixinAccessTokenDao.insert(weixinAccessToken);
            weixinAccessTokenLogDao.insert(log);

        } else {
            // 判断是否过期
            if (isExpires(weixinAccessToken)){
                //过期，重新获取ticket
                Long id = weixinAccessToken.getId();
                ReceiveAccessTokenDto dto = receiveAccessToken();
                weixinAccessToken = dtoToEntity(dto);
                weixinAccessToken.setId(id);
                WeixinAccessTokenLog log = dtoToEntityLog(dto);
                weixinAccessTokenDao.update(weixinAccessToken);
                weixinAccessTokenLogDao.insert(log);

            }

        }
        return weixinAccessToken.getAccessToken();
    }


    // 获取access_token
    public ReceiveAccessTokenDto receiveAccessToken() throws ServerException {
        WeixinPublic weixinPublic = weixinPublicService.getGlobleWeixinPublic();
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + weixinPublic.getAppId() + "&secret=" + weixinPublic.getAppSecret();

        String body = HttpUtil.httpGet(url);
        ObjectMapper mapper = new ObjectMapper();
        ReceiveAccessTokenDto bean = null;
        try {
            bean = mapper.readValue(body, ReceiveAccessTokenDto.class);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            throw new ServerException(HttpStatus.INTERNAL_SERVER_ERROR, "从微信服务器读取JsapiTicket时，将json转换为对象(" + JsapiTicketDto.class + ")报错。");
        }

        if (StringUtils.isNotBlank(bean.getErrcode())) {
            throw new ServerException(bean.getErrcode(),bean.getErrmsg());
        }

        EXPIRES_IN = Integer.valueOf(bean.getExpires_in());
        SEND_TIME = new Date();

        return bean;
    }


    private WeixinAccessToken dtoToEntity(ReceiveAccessTokenDto dto){
        WeixinAccessToken token=new WeixinAccessToken();
        token.setAccessToken(dto.getAccess_token());
        token.setCreateDate(new Date());
        token.setExpiresIn(Long.parseLong(dto.getExpires_in()));
        token.setUpdateDate(new Date());
        token.setWeixinPublicId(weixinConf.getPublicId());
        return token;
    }

    private WeixinAccessTokenLog dtoToEntityLog(ReceiveAccessTokenDto dto){
        WeixinAccessTokenLog tokenLog=new WeixinAccessTokenLog();

        if(StringUtils.isBlank(dto.getErrcode())){
            tokenLog.setAccessToken(dto.getAccess_token());
            tokenLog.setExpiresIn(Long.parseLong(dto.getExpires_in()));
        }else{
            tokenLog.setErrcode(dto.getErrcode());
            tokenLog.setErrmsg(dto.getErrmsg());
        }

        tokenLog.setCreateDate(new Date());
        tokenLog.setWeixinPublicId(weixinConf.getPublicId());
        return tokenLog;
    }

    /**
     * token是否过期
     *
     * @param token
     * @return boolean true:过期，false:未过期
     */
    public boolean isExpires(WeixinAccessToken token) {
        boolean isExpires = false;

        Calendar sendedCal = Calendar.getInstance();//
        sendedCal.setTime(token.getUpdateDate());
        sendedCal.add(Calendar.SECOND, token.getExpiresIn().intValue() - 120);//提前2分钟过期

        Calendar nowCal = Calendar.getInstance();
        nowCal.setTime(new Date());

        if (sendedCal.before(nowCal)) {
            isExpires = true;
        }

        return isExpires;
    }
}
